/*
*********************************************************************************************************
*                                              lwIP TCP/IP Stack
*                                    	 port for uC/OS-II RTOS on TIC6711 DSK
*
* File : sys_arch.c
* By   : ZengMing @ DEP,Tsinghua University,Beijing,China
* Reference: YangYe's source code for SkyEye project
*********************************************************************************************************
*/

//#include "lwip/debug.h"

#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"

#include "arch/sys_arch.h" 

static OS_MEM *pQueueMem;

//const void * const pvNullPointer;// = (void *)0xffffffff;

struct mem {
  /** index (-> ram[next]) of the next struct */
  mem_size_t next;
  /** index (-> ram[next]) of the next struct */
  mem_size_t prev;
  /** 1: this area is used; 0: this area is unused */
  u8_t used;
};

#if(MEM_SDRAM_USE_ENABLE)		//masda
//#define SIZEOF_STRUCT_MEM    (((sizeof(struct mem)) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
//#define MEM_SIZE_ALIGNED     (((MEM_SIZE) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
//#define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
//#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
//#define	T_ETHERNETIF_INPUT_STKSIZE		256
#include "Mem_Plan_SDRAM.h"
#if 0
#define LWIP_TASK_STK_ADDR	(SDRAM_OVER_ADDR + SDRAM_RESERVE_SINGLE)
#define LWIP_TASK_STK_SIZE	(sizeof(OS_STK) * LWIP_STK_SIZE * (LWIP_TASK_MAX+1))
#define T_ETHERNETIF_INPUT_STK_ADDR		(LWIP_TASK_STK_ADDR + LWIP_TASK_STK_SIZE + SDRAM_RESERVE_SINGLE)
#define T_ETHERNETIF_INPUT_STK_SIZE		(T_ETHERNETIF_INPUT_STKSIZE * sizeof(OS_STK))
#define PCQUEUEMEMORYPOOL_ADDR	(T_ETHERNETIF_INPUT_STK_ADDR + T_ETHERNETIF_INPUT_STK_SIZE + SDRAM_RESERVE_SINGLE)
#define PCQUEUEMEMORYPOOL_SIZE	(sizeof(char) * MAX_QUEUES * sizeof(TQ_DESCR) )
#define RAM_HEAP_ADDR	 (PCQUEUEMEMORYPOOL_ADDR + PCQUEUEMEMORYPOOL_SIZE + SDRAM_RESERVE_SINGLE)
#define RAM_HEAP_SIZE	(sizeof(u8_t) * (MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT))
#define MEMP_MEMORY_ADDR	(RAM_HEAP_ADDR + RAM_HEAP_SIZE + SDRAM_RESERVE_SINGLE)
#define MEMP_MEMORY_SIZE	(10691+1)
#endif

u8_t *ram_heap = (u8_t *)RAM_HEAP_ADDR;
u8_t *memp_memory = (u8_t *)MEMP_MEMORY_ADDR;
OS_STK *T_ETHERNETIF_INPUT_STK = (OS_STK *)T_ETHERNETIF_INPUT_STK_ADDR;
#endif

#if(MEM_SDRAM_USE_ENABLE)	//masda
static char *pcQueueMemoryPool = (char *)PCQUEUEMEMORYPOOL_ADDR;
#else
static char pcQueueMemoryPool[MAX_QUEUES * sizeof(TQ_DESCR) ];
#endif

#if 0
struct sys_timeouts lwip_timeouts[LWIP_TASK_MAX+1];
struct sys_timeouts null_timeouts;
#endif

#if(MEM_SDRAM_USE_ENABLE)	//masda
OS_STK *LWIP_TASK_STK[LWIP_TASK_MAX+1];
#else
OS_STK LWIP_TASK_STK[LWIP_TASK_MAX+1][LWIP_STK_SIZE];
#endif


/*-----------------------------------------------------------------------------------*/
/* This func should be called first in lwip task!
 * -------------------------------------------------		*/
void sys_init(void)
{
    u8_t i;
    u8_t   ucErr;

    //init mem used by sys_mbox_t //use ucosII functions
    pQueueMem = OSMemCreate( (void*)pcQueueMemoryPool, MAX_QUEUES, sizeof(TQ_DESCR), &ucErr );
    //init lwip_timeouts for every lwip task
    for(i=0;i<LWIP_TASK_MAX+1;i++){
	#if 0
    	lwip_timeouts[i].next = NULL;
	#endif
	#if(MEM_SDRAM_USE_ENABLE)	//masda		LWIP_TASK_STK_ADDR
	LWIP_TASK_STK[i] = (OS_STK *)(LWIP_TASK_STK_ADDR + i*LWIP_STK_SIZE*sizeof(OS_STK));
	#endif
    }

}


/*-----------------------------------------------------------------------------------*/
int sys_sem_valid(sys_sem_t *sem)
{
	if ((*sem) != NULL)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

void sys_sem_set_invalid(sys_sem_t *sem)
{
	(*sem) = NULL;
}

err_t sys_sem_new(sys_sem_t *sem, u8_t count)
{
	(*sem) = OSSemCreate((u16_t)count );
	if ((*sem) == NULL)
	{
		return ERR_MEM;
	}

	return ERR_OK;
}

/*-----------------------------------------------------------------------------------*/

void sys_sem_free(sys_sem_t *sem)
{
	u8_t     ucErr;
	OSSemDel((*sem), OS_DEL_NO_PEND, &ucErr );
}

/*-----------------------------------------------------------------------------------*/

void sys_sem_signal(sys_sem_t *sem)
{
    OSSemPost((*sem));
}

/*-----------------------------------------------------------------------------------*/

#if 0
u16_t sys_sem_accept(sys_sem_t sem)
{
    return OSSemAccept(sem );
}

extern volatile  INT32U  OSTime;
unsigned long sys_now(void)
{
	return OSTimeGet();
}

/*-----------------------------------------------------------------------------------*/
#endif

/*-----------------------------------------------------------------------------------*/

u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
  u8_t err;
  u32_t ucos_timeout;

  ucos_timeout = 0;
  if(timeout != 0){
  	ucos_timeout = (timeout * OS_TICKS_PER_SEC) / 1000;
  	if(ucos_timeout < 1)
  		ucos_timeout = 1;
  	else if(ucos_timeout > 65535) //ucOS only support u16_t pend
  		ucos_timeout = 65535;
  }
  	
  OSSemPend ((*sem),(u16_t)ucos_timeout, (u8_t *)&err);
  
  if(err == OS_TIMEOUT)
  	return SYS_ARCH_TIMEOUT;	// only when timeout!
  else
  	return (ucos_timeout - err)*(1000/ OS_TICKS_PER_SEC);
}

/*-----------------------------------------------------------------------------------*/
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
	u8_t       ucErr;
    
	(*mbox) = OSMemGet( pQueueMem, &ucErr );
	if( ucErr == OS_NO_ERR ) 
	{   
		(*mbox)->pQ = OSQCreate( &((*mbox)->pvQEntries[0]), size );       
		if( (*mbox)->pQ != NULL ) 
		{
			return ERR_OK;
		}
	} 
	return ERR_MEM;
}

int sys_mbox_valid(sys_mbox_t *mbox)
{
	if ((*mbox) != NULL)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

void sys_mbox_set_invalid(sys_mbox_t *mbox)
{
	(*mbox) = NULL;
}


/*-----------------------------------------------------------------------------------*/
void sys_mbox_free(sys_mbox_t *mbox)
{
    u8_t     ucErr;
    
    //clear OSQ EVENT
    OSQFlush( (*mbox)->pQ );
    //del OSQ EVENT
    (void)OSQDel( (*mbox)->pQ, OS_DEL_NO_PEND, &ucErr);
    //put mem back to mem queue
    ucErr = OSMemPut( pQueueMem, (*mbox) );
}

/*-----------------------------------------------------------------------------------*/
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
	//if( !msg ) 
	//msg = (void*)&pvNullPointer;
	OSQPost((*mbox)->pQ, msg);
}

/*-----------------------------------------------------------------------------------*/
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
    //if( !msg ) 
	//msg = (void*)&pvNullPointer;
    if (OS_NO_ERR != OSQPost((*mbox)->pQ, msg))
    {
    	return ERR_MEM;
    }
	return ERR_OK;
}

/*-----------------------------------------------------------------------------------*/
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
    u8_t     ucErr;
    u32_t ucos_timeout;


  ucos_timeout = 0;
  if(timeout != 0)
  {
	  ucos_timeout = (timeout * OS_TICKS_PER_SEC)/1000;
	  if(ucos_timeout < 1)
	  	ucos_timeout = 1;
	  else if(ucos_timeout > 65535)	//ucOS only support u16_t timeout
	  	ucos_timeout = 65535;
  }  
    
  if(msg != NULL){
    *msg = OSQPend((*mbox)->pQ, (u16_t)ucos_timeout, &ucErr );        
  }else{
    //just discard return value if msg==NULL
    OSQPend((*mbox)->pQ,(u16_t)ucos_timeout,&ucErr);
  }
    
  if( ucErr == OS_TIMEOUT ) 
  {
     timeout = SYS_ARCH_TIMEOUT;
  }
  else 
  {
      //if(*msg == (void*)&pvNullPointer ) 
      //{
	  //	*msg = NULL;
      //}
      #if 0	//masda
  if(msg == NULL)
  {
  }
	  if (*msg == NULL)
	  {
	  }
      #endif
     timeout = (ucos_timeout -ucErr)*(1000/ OS_TICKS_PER_SEC);
  }
    
  return timeout;
}

  
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{   
   u8_t     ucErr;   
      
  *msg = OSQAccept((*mbox)->pQ,&ucErr);   
     
  if(*msg == ((void *)0))  
    return SYS_MBOX_EMPTY;   
  else   
    return 0;   
}   


/*----------------------------------------------------------------------*/
#if 0
struct 
sys_timeouts * sys_arch_timeouts(void)
{
  u8_t curr_prio;
  s16_t offset;
  
  OS_TCB curr_task_pcb;
  
  null_timeouts.next = NULL;
  
  OSTaskQuery(OS_PRIO_SELF,&curr_task_pcb);
  curr_prio = curr_task_pcb.OSTCBPrio;
  	
  offset = curr_prio - LWIP_START_PRIO;

  if(curr_prio == TCPIP_THREAD_PRIO) 
  {
  	return &lwip_timeouts[LWIP_TASK_MAX];
  }
  else if(offset >= 0 && offset < LWIP_TASK_MAX)
  {
  	return &lwip_timeouts[offset];
  }
  else
  {
  	return &null_timeouts;
  }
  
  //if not called by a lwip task ,return timeouts->NULL
}
#endif

/*------------------------------------------------------------------------*/
//sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
  /** @todo Replace LWIP_TASK_STK by the use of "stacksize" parameter */
  if(prio == TCPIP_THREAD_PRIO){
	OSTaskCreate(thread, (void *)arg, &LWIP_TASK_STK[LWIP_TASK_MAX][LWIP_STK_SIZE-1], prio);
		return prio;
  }  
  else if(prio - LWIP_START_PRIO  < LWIP_TASK_MAX){  
	OSTaskCreate(thread, (void *)arg, &LWIP_TASK_STK[prio - LWIP_START_PRIO][LWIP_STK_SIZE-1], prio);
		return prio;
  }
  else {
		//xprintf(" lwip task prio out of range ! error! ");		//masda
		return 0;
  }
}










